########################################################################
#  Searx-Qt - Lightweight desktop application for Searx.
#  Copyright (C) 2020-2022  CYBERDEViL
#
#  This file is part of Searx-Qt.
#
#  Searx-Qt is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  Searx-Qt is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
########################################################################


import html
from urllib.parse import quote

from searxqt.utils.string import formatFileSize, formatFileCount
from searxqt.translations import _


class HtmlGen:
    def wrapHtml(bodyStr, styleStr=""):
        return f"""
<html>
  <head>
    <style>{styleStr}</style>
  </head>
  <body>
    {bodyStr}
  </body>
</html>"""


class FailedResponsesHtml:
    def create(results, message, css):
        """
        @param result: List with failed search result object (searxqt.core.requests.Result).
        @type result: list

        @param message: TODO
        

        @param css: Optionaly set a stylesheet, it should be the content only;
                    so do not include the <style> tags!
        @type css: str
        """

        body = f"<p id=\"top-message\">{message}</p>" \
               f"<h3>{_('Failed requests')}:</h3>" \
               "<table class=\"fail\">"

        lastResult = results[-1]

        for result in results:
            url = result.url()
            error = html.escape(result.error())
            content = html.escape(result.text())
            body += "<tr>" \
                    "<td colspan=\"2\" class=\"fail-instance\">" \
                   f"<a href=\"{url}\">{url}</a>" \
                    "</td></tr>" \
                    "<tr>" \
                   f"<td class=\"fail-prefix\">{_('Error')}</td>" \
                   f"<td class=\"fail-value\">{error}</td>" \
                    "</tr>" \
                    "<tr>" \
                   f"<td class=\"fail-prefix\">{_('Content')}</td>" \
                   f"<td class=\"fail-value\">{content}</td>" \
                    "</tr>"

            if result != lastResult:
                body += "<tr><td colspan=\"2\"><hr></td></tr>"

        body += "</table>"
        return HtmlGen.wrapHtml(body, css)


class ResultsHtml:
    """ Create HTML from a valid search response.
    """

    def create(jsonResult, css):
        """
        @param jsonResult: The josn result of a search response.
        @type jsonResult: json or dict

        @param css: Optionaly set a stylesheet, it should be the content only;
                    so do not include the <style> tags!
        @type css: str
        """
        elemStr = ""

        # Search query suggestions
        data = jsonResult.get('suggestions', [])
        if data:
            elemStr += ResultsHtml.createHrefListElement(
                'search', _('Suggestions'), data
            )
            elemStr += "<hr>"

        # Search query corrections
        data = jsonResult.get('corrections', [])
        if data:
            elemStr += ResultsHtml.createHrefListElement(
                'search', _('Corrections'), data
            )
            elemStr += "<hr>"

        # Unresponsive engines
        data = jsonResult.get('unresponsive_engines', [])
        if data:
            elemStr += ResultsHtml.createUnresponsiveEnginesElement(data)
            elemStr += "<hr>"

        # Infoboxes
        data = jsonResult.get('infoboxes', [])
        if data:
            elemStr += "<p id=\"infoboxes_header\">Infoboxes</p>"
            for infoboxData in data:
                elemStr += ResultsHtml.createInfobox(infoboxData)

        # Answers
        data = jsonResult.get('answers', [])
        if data:
            elemStr += ResultsHtml.createStrListElement(_('Answers'), data)
            elemStr += "<hr>"

        # Results
        data = jsonResult.get('results', [])
        if data:
            for resultData in data:
                elemStr += ResultsHtml.createResultElement(resultData)

        return HtmlGen.wrapHtml(elemStr, css)

    def createStrListElement(title, data):
        elemStr = " | ".join([html.escape(entry) for entry in data])
        return ResultsHtml.createListContainer(title, elemStr)

    def createHrefListElement(scheme, title, data):
        elemStr = ""
        scheme += ":"
        for entry in data:
            if elemStr:
                elemStr += " | "
            url = scheme + quote(entry)
            elemStr += f"<a href=\"{url}\">{html.escape(entry)}</a>"
        return ResultsHtml.createListContainer(title, elemStr)

    def createListContainer(title, elems):
        return f"<div class=\"{title}\"><b>{title}</b>: {elems}</div>"

    def createUnresponsiveEnginesElement(data):
        elemStr = ""
        for name, error in data:
            if elemStr:
                elemStr += " | "
            elemStr += f"{html.escape(name)} <i>({html.escape(error)})</i>"
        return ResultsHtml.createListContainer(_('Unresponsive engines'), elemStr)

    def createInfobox(infoboxData):
        # Create new infobox
        elemStr = "<div class=\"infobox\">"

        # Title
        data = html.escape(infoboxData.get("infobox", "-"))
        elemStr += "<center><div class=\"infobox_title\">" \
                   f"{data}</div></center>"

        # ID
        data = infoboxData.get("id", None)
        if data:
            data = html.escape(data)
            elemStr += "<center><div class=\"infobox_id\">" \
                       f"<a href=\"{data}\">{data}</a></div></center>"

        # Content
        data = infoboxData.get("content", None)
        if data:
            data = html.escape(data)
            elemStr += f"<div class=\"infobox_content\">{data}</div>"

        # Attributes
        data = infoboxData.get("attributes", None)
        if data:
            elemStr += "<p class=\"infobox_attr_head\">Attributes</p>"
            elemStr += "<table class=\"infobox_attr_table\">"
            for attributeData in data:
                # TODO for now skip images ..
                if "value" not in attributeData:
                    continue

                # New row
                elemStr += "<tr>"
                value = html.escape(attributeData.get('label', ''))
                elemStr += f"<td class=\"infobox_label\">{value}</td>"
                value = html.escape(attributeData.get('value', ''))
                elemStr += f"<td class=\"infobox_value\">{value}</td>"
                elemStr += "</tr>"
            elemStr += "</table>"

        # Urls list
        data = infoboxData.get("urls", None)
        if data:
            elemStr += "<p class=\"infobox_links_head\">Links</p>"
            elemStr += "<ul class=\"infobox_link_list\">"
            for urlData in data:
                url = html.escape(urlData.get("url"))
                title = html.escape(urlData.get("title", "-"))
                elemStr += "<li class=\"infobox_link_list_item\">" \
                           f"<a href=\"{url}\" title=\"{url}\">{title}</a>" \
                           "</li>"

            elemStr += "</ul>"

        # Engines
        data = infoboxData.get("engines", None)
        if data:
            elemStr += ResultsHtml.createStrListElement(_('Engines'), data)

        # Closing tag of the new infobox element.
        elemStr += "</div>"
        elemStr += "<hr>"

        return elemStr

    def createResultElement(data):
        # Create general elements
        title=html.escape(data.get('title', ''))
        url=html.escape(data.get('url', ''))
        content=html.escape(data.get('content', ''))

        engine = ''
        for e in data.get('engines', []):
            engine += f"{e} "
        engine = engine.rstrip()

        elemStr = "<div class=\"results\">" \
                  f"<h4 class=\"result-title\"><i>{engine}: </i>" \
                  f"<a href=\"{url}\">{title}</a></h4>" \
                  "<div style=\"margin-left: 10px;\">" \
                  f"<p class=\"result-description\">{content}</p>" \
                  f"<p class=\"result-url\">{url}</p>"

        # Add file data elements
        elemStr += ResultsHtml.createFileSection(data)

        elemStr += "</div></div>"
        return elemStr

    def createFileSection(data):
        elemStr = ""

        value = data.get('magnetlink', '')
        if value:
            value = html.escape(value)
            elemStr += f"<a href=\"{value}\">Magnet</a> "

        value = data.get('torrentfile', '')
        if value:
            value = html.escape(value)
            elemStr += f"<a href=\"{value}\">Torrent</a> "

        value = data.get('filesize', 0)
        if value:
            elemStr += formatFileSize(value) + " "

        value = data.get('files', 0)
        if value:
            elemStr += formatFileCount(value) + " "

        value = data.get('seed', None)
        if value is not None:
            value = html.escape(str(value))
            elemStr += f"seeders: {value} "

        value = data.get('leech', None)
        if value is not None:
            value = html.escape(str(value))
            elemStr += f"leechers: {value} "

        value = data.get('img_format', "")
        if value:
            value = html.escape(value)
            elemStr += f"format: {value} "

        if elemStr:
            elemStr = "<p class=\"result-file\">" + elemStr + "</p>"

        return elemStr
